# Copyright (c) 2013, Ruslan Baratov
# All rights reserved.

cmake_minimum_required(VERSION 3.0)
project(Hunter)

include(ExternalProject) # ExternalProject_Add

# Scheme for download and install ios universal boost library

list(APPEND CMAKE_MODULE_PATH "@HUNTER_SELF@/cmake/modules")

include(hunter_boost_component_b2_args)
include(hunter_dump_cmake_flags)
include(hunter_install_boost_config)
include(hunter_internal_error)
include(hunter_status_debug)
include(hunter_assert_not_empty_string)
include(hunter_unsetvar)
include(hunter_get_boost_libs)
include(hunter_parse_boost_config_macros)

hunter_status_debug("Scheme: url_sha1_boost_ios_library")

# Check preconditions
hunter_assert_not_empty_string("@HUNTER_SELF@")
hunter_assert_not_empty_string("@HUNTER_EP_NAME@")
hunter_assert_not_empty_string("@HUNTER_PACKAGE_URL@")
hunter_assert_not_empty_string("@HUNTER_PACKAGE_SHA1@")
hunter_assert_not_empty_string("@HUNTER_PACKAGE_DOWNLOAD_DIR@")
hunter_assert_not_empty_string("@HUNTER_PACKAGE_SOURCE_DIR@")
hunter_assert_not_empty_string("@HUNTER_PACKAGE_BUILD_DIR@")
hunter_assert_not_empty_string("@HUNTER_PACKAGE_INSTALL_PREFIX@")
hunter_assert_not_empty_string("@HUNTER_PACKAGE_COMPONENT@")
hunter_assert_not_empty_string("@HUNTER_GLOBAL_SCRIPT_DIR@")
hunter_assert_not_empty_string("@HUNTER_PACKAGE_SCRIPT_DIR@")
hunter_assert_not_empty_string("@HUNTER_TLS_VERIFY@")

# Note: support for single architecture/native iOS builds (i.e., arm64)
hunter_assert_not_empty_string("@IPHONESIMULATOR_ARCHS@@IPHONEOS_ARCHS@")
hunter_assert_not_empty_string("@IPHONESIMULATOR_ROOT@")
hunter_assert_not_empty_string("@IPHONEOS_ROOT@")
hunter_assert_not_empty_string("@IPHONEOS_SDK_ROOT@")
hunter_assert_not_empty_string("@IPHONESIMULATOR_SDK_ROOT@")
hunter_assert_not_empty_string("@HUNTER_Boost_VERSION@")

# get list of boost components for given version
hunter_get_boost_libs(VERSION "@HUNTER_Boost_VERSION@" LIBS boost_libs)

if("@HUNTER_Boost_VERSION@" VERSION_EQUAL 1.66.0)
  set(fatlib_script "@HUNTER_PACKAGE_SCRIPT_DIR@/create-boost-1-66-ios-fatlib.sh")
else()
  set(fatlib_script "@HUNTER_PACKAGE_SCRIPT_DIR@/create-boost-ios-fatlib.sh")
endif()

set(libfound NO)
foreach(x ${boost_libs})
  string(COMPARE EQUAL "${x}" "@HUNTER_PACKAGE_COMPONENT@" result)
  if(result)
    set(libfound YES)
  endif()
endforeach()

if(NOT libfound)
  hunter_internal_error("No such library")
endif()

set(has_iphoneos FALSE)
set(has_isim FALSE)

set(iphoneos_archs "")
set(arm_instruction_set "")
set(is_first YES)
foreach(x @IPHONEOS_ARCHS@)
  string(COMPARE EQUAL "${x}" "arm64" is_arm64)
  if(is_first AND NOT is_arm64)
    # First goes to instruction-set option;
    # arm64 is not supported:
    #   * https://svn.boost.org/trac/boost/ticket/10910
    # NOTE:
    #   Being in instruction-set is not enough, should be
    #   mentioned explicitly in C++ flags too (Boost 1.66)
    set(arm_instruction_set "${x}")
    set(is_first NO)
  endif()

  set(iphoneos_archs "${iphoneos_archs} -arch ${x}")

  # Has at least one iPhoneOS architecture to build
  set(has_iphoneos TRUE)
endforeach()

string(COMPARE EQUAL "${arm_instruction_set}" "" no_instruction_set)
if(no_instruction_set)
  # set default value (for build with one arm64)
  set(arm_instruction_set "armv7")
endif()

set(isim_archs "")
foreach(x @IPHONESIMULATOR_ARCHS@)
  set(isim_archs "${isim_archs} -arch ${x}")
  set(has_isim TRUE)
endforeach()

set(boost_user_jam "@HUNTER_PACKAGE_BUILD_DIR@/boost.user.jam")
file(
     WRITE
     ${boost_user_jam}
     "using darwin : iphoneos\n"
     "    : xcrun clang++ ${iphoneos_archs} -isysroot @IPHONEOS_SDK_ROOT@\n"
     "    : <striper> <root>@IPHONEOS_ROOT@\n"
     "    : <architecture>arm <target-os>iphone\n"
     ";\n"
     "\n"
     "using darwin : iphonesimulator\n"
     "    : xcrun clang++ ${isim_archs} -isysroot @IPHONESIMULATOR_SDK_ROOT@\n"
     "    : <striper> <root>@IPHONESIMULATOR_ROOT@\n"
     "    : <architecture>x86 <target-os>iphone\n"
     ";"
)

file(READ ${boost_user_jam} boost_user_jam_content)
hunter_status_debug("boost.user.jam content:\n${boost_user_jam_content}")

set(
    build_opts
    -a
    link=static
    threading=multi
    variant=release,debug
    define=BOOST_SP_NO_SYNC
    --layout=tagged
    --user-config="${boost_user_jam}"
)

if (@HUNTER_Boost_VERSION@ VERSION_GREATER_EQUAL 1.72.0 AND NOT USE_CONFIG_FROM_BOOST)
  list(APPEND build_opts --no-cmake-config )
endif()

set(BOOST_VERSION "@HUNTER_Boost_VERSION@")

# Use:
# * BOOST_VERSION
hunter_boost_component_b2_args(
  "@HUNTER_PACKAGE_COMPONENT@"
  "@HUNTER_Boost_CMAKE_ARGS@"
  b2_component_opts
  )

list(APPEND build_opts ${b2_component_opts})

hunter_dump_cmake_flags()
# -> CMAKE_CXX_FLAGS

if(CMAKE_CXX_FLAGS)
  list(APPEND build_opts "cxxflags=${CMAKE_CXX_FLAGS}")
endif()

string(COMPARE NOTEQUAL "@HUNTER_JOBS_OPTION@" "" have_jobs)
if(have_jobs)
  if("@HUNTER_JOBS_OPTION@" GREATER "256")
    list(APPEND build_opts "-j" 256)
  else()
    list(APPEND build_opts "-j" "@HUNTER_JOBS_OPTION@")
  endif()
endif()

set(
    build_opts_iphoneos
    toolset=darwin-iphoneos
    target-os=iphone
    architecture=arm
    instruction-set=${arm_instruction_set}
    ${build_opts}
)

set(
    build_opts_iphonesimulator
    toolset=darwin-iphonesimulator
    target-os=iphone
    architecture=x86
    ${build_opts}
)

# Clear Xcode environment
set(
    bootstrap
    . "@HUNTER_GLOBAL_SCRIPT_DIR@/clear-all.sh" &&
    ./bootstrap.sh
    "--with-libraries=@HUNTER_PACKAGE_COMPONENT@"
    "--prefix=@HUNTER_PACKAGE_INSTALL_PREFIX@"
)

if(@HUNTER_STATUS_DEBUG@)
  set(verbose_output "-d+2 --debug-configuration")
endif()

if(has_iphoneos)
  ExternalProject_Add(
      "@HUNTER_EP_NAME@-ios"
      URL
      @HUNTER_PACKAGE_URL@
      URL_HASH
      SHA1=@HUNTER_PACKAGE_SHA1@
      DOWNLOAD_DIR
      "@HUNTER_PACKAGE_DOWNLOAD_DIR@"
      TLS_VERIFY
      "@HUNTER_TLS_VERIFY@"
      SOURCE_DIR
      "@HUNTER_PACKAGE_SOURCE_DIR@"
      INSTALL_DIR
      "@HUNTER_PACKAGE_INSTALL_PREFIX@"
          # not used, just avoid creating Install/<name> empty directory
      CONFIGURE_COMMAND
      ${bootstrap}
      BUILD_COMMAND
      ./b2
      ${verbose_output}
      ${build_opts_iphoneos}
      BUILD_IN_SOURCE
      1
      INSTALL_COMMAND
      ./b2
      -d0
      ${build_opts_iphoneos}
      install
      "--prefix=@HUNTER_PACKAGE_INSTALL_PREFIX@"  
  )
else()
  # Add dummy target
  ExternalProject_Add(
      "@HUNTER_EP_NAME@-ios"
      URL
      @HUNTER_PACKAGE_URL@
      URL_HASH
      SHA1=@HUNTER_PACKAGE_SHA1@
      DOWNLOAD_DIR
      "@HUNTER_PACKAGE_DOWNLOAD_DIR@"
      TLS_VERIFY
      "@HUNTER_TLS_VERIFY@"
      SOURCE_DIR
      "@HUNTER_PACKAGE_SOURCE_DIR@"
      INSTALL_DIR
      "@HUNTER_PACKAGE_INSTALL_PREFIX@"
          # not used, just avoid creating Install/<name> empty directory
      DOWNLOAD_COMMAND
      ""
      CONFIGURE_COMMAND
      ""
      BUILD_COMMAND
      ""
      INSTALL_COMMAND
      ""
  )
endif()

if(has_isim)
  ExternalProject_Add(
      "@HUNTER_EP_NAME@-ios_sim"
      DOWNLOAD_COMMAND
      ""
      DOWNLOAD_DIR
      "@HUNTER_PACKAGE_DOWNLOAD_DIR@"
      TLS_VERIFY
      "@HUNTER_TLS_VERIFY@"
      SOURCE_DIR
      "@HUNTER_PACKAGE_SOURCE_DIR@"
      INSTALL_DIR
      "@HUNTER_PACKAGE_INSTALL_PREFIX@"
          # not used, just avoid creating Install/<name> empty directory
      CONFIGURE_COMMAND
      ${bootstrap}
      BUILD_COMMAND
      ./b2
      ${verbose_output}
      ${build_opts_iphonesimulator}
      BUILD_IN_SOURCE
      1
      INSTALL_COMMAND
      ./b2
      -d0
      ${build_opts_iphonesimulator}
      install
      "--prefix=@HUNTER_PACKAGE_INSTALL_PREFIX@"  
  )
else()
  # Add dummy target
  ExternalProject_Add(
      "@HUNTER_EP_NAME@-ios_sim"
      URL
      @HUNTER_PACKAGE_URL@
      URL_HASH
      SHA1=@HUNTER_PACKAGE_SHA1@
      DOWNLOAD_DIR
      "@HUNTER_PACKAGE_DOWNLOAD_DIR@"
      TLS_VERIFY
      "@HUNTER_TLS_VERIFY@"
      SOURCE_DIR
      "@HUNTER_PACKAGE_SOURCE_DIR@"
      INSTALL_DIR
      "@HUNTER_PACKAGE_INSTALL_PREFIX@"
          # not used, just avoid creating Install/<name> empty directory
      DOWNLOAD_COMMAND
      ""
      CONFIGURE_COMMAND
      ""
      BUILD_COMMAND
      ""
      INSTALL_COMMAND
      ""
  )
endif()

add_dependencies(
    "@HUNTER_EP_NAME@-ios_sim"
    "@HUNTER_EP_NAME@-ios"
)

string(COMPARE EQUAL "@HUNTER_PACKAGE_COMPONENT@" "test" is_test)
if(is_test)
  set(LIBNAME unit_test_framework)
else()
  set(LIBNAME "@HUNTER_PACKAGE_COMPONENT@")
endif()

string(COMPARE EQUAL "@HUNTER_PACKAGE_COMPONENT@" "log" log_setup_target)
if(log_setup_target)
  set(
      extra_lib_command
      COMMAND
      ${fatlib_script}
      "@HUNTER_PACKAGE_SOURCE_DIR@"
      "log_setup"
      "@HUNTER_PACKAGE_COMPONENT@"
      "@HUNTER_PACKAGE_INSTALL_PREFIX@/lib"
  )
else()
  set(extra_lib_command "")
endif()

hunter_parse_boost_config_macros(BOOST_CONFIG_MACROS "@HUNTER_Boost_CMAKE_ARGS@")
configure_file(
  "@HUNTER_GLOBAL_SCRIPT_DIR@/append-boost-config-macros.cmake.in"
  "@HUNTER_PACKAGE_BUILD_DIR@/append-boost-config-macros.cmake"
  @ONLY
)

ExternalProject_Add(
    "@HUNTER_EP_NAME@-ios_universal"
    DEPENDS
    "@HUNTER_EP_NAME@-ios"
    "@HUNTER_EP_NAME@-ios_sim"
    DOWNLOAD_COMMAND
    ""
    TLS_VERIFY
    "@HUNTER_TLS_VERIFY@"
    DOWNLOAD_DIR
    "@HUNTER_PACKAGE_DOWNLOAD_DIR@"
    SOURCE_DIR
    "@HUNTER_PACKAGE_SOURCE_DIR@"
    INSTALL_DIR
    "@HUNTER_PACKAGE_INSTALL_PREFIX@"
        # not used, just avoid creating Install/<name> empty directory
    UPDATE_COMMAND
    "@CMAKE_COMMAND@" -P
    "@HUNTER_PACKAGE_BUILD_DIR@/append-boost-config-macros.cmake"
    CONFIGURE_COMMAND
    ""
    BUILD_COMMAND
    ""
    INSTALL_COMMAND
    "${CMAKE_COMMAND}" -E make_directory "@HUNTER_PACKAGE_INSTALL_PREFIX@/lib"
    COMMAND
    ${fatlib_script}
    "@HUNTER_PACKAGE_SOURCE_DIR@"
    "${LIBNAME}"
    "@HUNTER_PACKAGE_COMPONENT@"
    "@HUNTER_PACKAGE_INSTALL_PREFIX@/lib"
    ${extra_lib_command}
)

# Forward some variables
set(HUNTER_SELF "@HUNTER_SELF@")
set(HUNTER_PACKAGE_INSTALL_PREFIX "@HUNTER_PACKAGE_INSTALL_PREFIX@")
set(HUNTER_Boost_VERSION "@HUNTER_Boost_VERSION@")

if(NOT USE_CONFIG_FROM_BOOST OR HUNTER_Boost_VERSION VERSION_LESS 1.72.0)
  hunter_install_boost_config()
endif()
